﻿using System;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using vm.Aspects.Parsers;

namespace vm.Aspects.Tests
{
    [TestClass()]
    public class DsvReaderTest
    {
        public TestContext TestContext { get; set; }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        #region Constructors
        [TestMethod()]
        public void ReaderConstructorTestCsv()
        {
            var target = new DsvReader();

            Assert.IsNotNull(target);
        }

        [TestMethod()]
        public void ReaderConstructorTestTsv()
        {
            string fieldSeparators = "\t";
            string recordSeparators = "\r\n";
            string fileSeparators = "\u001a\uffff";
            string recordMark = null;

            var target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);

            Assert.IsNotNull(target);
        }

        [TestMethod()]
        public void ReaderConstructorTestBsv()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a\uffff";
            string recordMark = null;

            var target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);

            Assert.IsNotNull(target);
        }

        [TestMethod()]
        public void ReaderConstructorTestBsvNull3()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = null;
            string recordMark = null;

            var target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);

            Assert.IsNotNull(target);
        }
        #endregion

        [TestMethod()]
        public void IsRecordSeparatorTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            Assert.IsTrue((bool)_target.Invoke("IsRecordSeparator", '\r'));
            Assert.IsTrue((bool)_target.Invoke("IsRecordSeparator", '\n'));
            Assert.IsFalse((bool)_target.Invoke("IsRecordSeparator", 'a'));
        }


        [TestMethod()]
        public void IsRecordSeparatorTest1()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);

            Assert.IsTrue((bool)_target.Invoke("IsRecordSeparator", '\r'));
            Assert.IsTrue((bool)_target.Invoke("IsRecordSeparator", '\n'));
            Assert.IsTrue((bool)_target.Invoke("IsRecordSeparator", '~'));
            Assert.IsFalse((bool)_target.Invoke("IsRecordSeparator", 'a'));
        }

        [TestMethod()]
        public void IsFileSeparatorTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            Assert.IsTrue((bool)_target.Invoke("IsFileSeparator", '\u001a'));
            Assert.IsTrue((bool)_target.Invoke("IsFileSeparator", '\uffff'));
            Assert.IsFalse((bool)_target.Invoke("IsFileSeparator", '\u0000'));
        }

        [TestMethod()]
        public void IsFieldSeparatorTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            Assert.IsTrue((bool)_target.Invoke("IsFieldSeparator", ','));
            Assert.IsFalse((bool)_target.Invoke("IsFieldSeparator", '\n'));
            Assert.IsFalse((bool)_target.Invoke("IsFieldSeparator", '\"'));
        }

        [TestMethod()]
        public void IsFieldSeparatorTest1()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);

            Assert.IsTrue((bool)_target.Invoke("IsFieldSeparator", '|'));
            Assert.IsFalse((bool)_target.Invoke("IsFieldSeparator", ','));
            Assert.IsFalse((bool)_target.Invoke("IsFieldSeparator", '\n'));
            Assert.IsFalse((bool)_target.Invoke("IsFieldSeparator", '\"'));
        }

        [TestMethod()]
        public void IsFieldMarkTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            Assert.IsTrue((bool)_target.Invoke("IsFieldMark", '\"'));
            Assert.IsFalse((bool)_target.Invoke("IsFieldMark", '\''));
            Assert.IsFalse((bool)_target.Invoke("IsFieldMark", ','));
        }

        [TestMethod()]
        public void IsEndOfRecordOrFileTest()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);

            Assert.IsFalse((bool)_target.Invoke("IsEndOfRecordOrFile", '|'));
            Assert.IsTrue((bool)_target.Invoke("IsEndOfRecordOrFile", '\r'));
            Assert.IsTrue((bool)_target.Invoke("IsEndOfRecordOrFile", '\n'));
            Assert.IsTrue((bool)_target.Invoke("IsEndOfRecordOrFile", '~'));
            Assert.IsFalse((bool)_target.Invoke("IsEndOfRecordOrFile", 'a'));
            Assert.IsTrue((bool)_target.Invoke("IsEndOfRecordOrFile", '\u001a'));
            Assert.IsTrue((bool)_target.Invoke("IsEndOfRecordOrFile", '\uffff'));
            Assert.IsFalse((bool)_target.Invoke("IsEndOfRecordOrFile", '\u0000'));
        }

        [TestMethod()]
        public void PeekNextCharTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(" \t\v\n"));
            Assert.AreEqual((char)_target.Invoke("PeekNextChar"), ' ');
            Assert.AreEqual((char)_target.Invoke("ReadNextChar"), ' ');

            _target.SetField("_reader", new StringReader(""));
            Assert.AreEqual((char)_target.Invoke("PeekNextChar"), '\uffff');
            Assert.AreEqual((char)_target.Invoke("ReadNextChar"), '\uffff');

            _target.SetField("_reader", new StringReader(@"@#$%jkaf 
weoryt987423\u0000\u001a  aASDFсадфгхйъуи"));
            do
            {
                Assert.AreEqual((char)_target.Invoke("PeekNextChar"), (char)_target.Invoke("ReadNextChar"));
            }
            while ((char)_target.Invoke("ReadNextChar") == '\uffff');
        }

        [TestMethod()]
        public void SkipWhitespacesTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(" \t\v\n"));
            Assert.AreEqual((char)_target.Invoke("SkipWhitespaces"), '\n');

            _target.SetField("_reader", new StringReader(" \t\v,"));
            Assert.AreEqual((char)_target.Invoke("SkipWhitespaces"), ',');

            _target.SetField("_reader", new StringReader(" \t\v"));
            Assert.AreEqual((char)_target.Invoke("SkipWhitespaces"), '\uffff');
        }

        [TestMethod()]
        public void GetMarkedFieldTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader("\"f"));
            Assert.AreEqual((string)_target.Invoke("GetMarkedField"), "f");
        }

        [TestMethod()]
        [ExpectedException(typeof(InvalidDataException))]
        public void GetMarkedFieldTest1()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader("f\""));
            Assert.AreEqual((char)_target.Invoke("GetMarkedField"), 'f');
        }

        [TestMethod()]
        public void SkipFieldsSeparatorTest()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);
            _target.SetField("_reader", new StringReader("|7"));
            Assert.AreEqual((char)_target.Invoke("SkipFieldsSeparator"), '7');
        }

        [TestMethod()]
        [ExpectedException(typeof(InvalidDataException))]
        public void SkipFieldsSeparatorTest1()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);
            _target.SetField("_reader", new StringReader("7|"));
            Assert.AreEqual((char)_target.Invoke("SkipFieldsSeparator"), '7');
        }

        [TestMethod()]
        public void SkipEndOfRecordTest()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);
            _target.SetField("_reader", new StringReader("~\r\nj"));
            Assert.AreEqual((char)_target.Invoke("SkipEndOfRecord"), 'j');
        }

        [TestMethod()]
        [ExpectedException(typeof(InvalidDataException))]
        public void SkipEndOfRecordTest1()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);
            _target.SetField("_reader", new StringReader("1~\r\nj"));
            Assert.AreEqual((char)_target.Invoke("SkipEndOfRecord"), 'j');
        }

        [TestMethod()]
        public void GetFieldTest()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);
            _target.SetField("_reader", new StringReader("abcd"));
            Assert.AreEqual((string)_target.Invoke("GetField"), "abcd");
        }

        [TestMethod()]
        public void GetFieldTest1()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);
            _target.SetField("_reader", new StringReader("abcd|"));
            Assert.AreEqual((string)_target.Invoke("GetField"), "abcd");
        }

        [TestMethod()]
        public void GetFieldTest2()
        {
            string fieldSeparators = "|";
            string recordSeparators = "~\r\n";
            string fileSeparators = "\u001a";
            string recordMark = null;

            DsvReader target = new DsvReader(fieldSeparators, recordSeparators, fileSeparators, recordMark);
            var _target = new PrivateObject(target);
            _target.SetField("_reader", new StringReader(" abcd   |"));
            Assert.AreEqual((string)_target.Invoke("GetField"), "abcd");
        }

        [TestMethod()]
        public void GetMarkedFieldTest0()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader("\"abcd\""));
            Assert.AreEqual((string)_target.Invoke("GetMarkedField"), "abcd");
        }

        [TestMethod()]
        public void GetMarkedFieldTest10()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader("\" abcd \""));
            Assert.AreEqual((string)_target.Invoke("GetMarkedField"), " abcd ");
        }

        [TestMethod()]
        public void GetMarkedFieldTest2()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader("\"abcd\","));
            Assert.AreEqual((string)_target.Invoke("GetMarkedField"), "abcd");
        }

        [TestMethod()]
        public void GetMarkedFieldTest3()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(@""" abcd
efgh  """));
            Assert.AreEqual((string)_target.Invoke("GetMarkedField"), @" abcd
efgh  ");
        }

        [TestMethod()]
        public void GetMarkedFieldTest4()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(@""" abcd"));
            Assert.AreEqual((string)_target.Invoke("GetMarkedField"), @" abcd");
        }

        public static bool AreEqual(string[] left, string[] right)
        {
            if (left == null)
                return right == null;
            if (right == null)
                return false;

            if (left.Length != right.Length)
                return false;

            for (var i=0; i<left.Length; i++)
                if (left[i] != right[i])
                    return false;

            return true;
        }

        public static bool AreEqual(string[][] left, string[][] right)
        {
            if (left == null)
                return right == null;
            if (right == null)
                return false;

            if (left.Length != right.Length)
                return false;

            for (var i=0; i<left.Length; i++)
                if (!AreEqual(left[i], right[i]))
                    return false;

            return true;
        }

        [TestMethod()]
        public void GetRecordTest()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(@"abc,123,!@#"));

            Assert.IsTrue(AreEqual((string[])_target.Invoke("GetRecord"), new string[] { "abc", "123", "!@#" }));
        }

        [TestMethod()]
        public void GetRecordTest1()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(@"""abc"",""123"",""!@#"""));

            Assert.IsTrue(AreEqual((string[])_target.Invoke("GetRecord"), new string[] { "abc", "123", "!@#" }));
        }


        [TestMethod()]
        public void GetRecordTest2()
        {
            DsvReader target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(@"""abc"",""123"",""!@#""
"));

            Assert.IsTrue(AreEqual((string[])_target.Invoke("GetRecord"), new string[] { "abc", "123", "!@#" }));
        }

        [TestMethod()]
        public void GetRecordTest3()
        {
            var target = new DsvReader();
            var _target = new PrivateObject(target);

            _target.SetField("_reader", new StringReader(@"abc,123,!@#
"));

            Assert.IsTrue(AreEqual((string[])_target.Invoke("GetRecord"), new string[] { "abc", "123", "!@#" }));
        }

        [TestMethod()]
        public void ReadTest()
        {
            var target = new DsvReader();
            var text = 
@"Field1,Field1,""Field,3""
aaa,qqq,ccc
""qwer , 1234"",""aaa
 bbb"",qqq
";
            var expected = new string[][] 
            {
                new string[] {"Field1", "Field1", "Field,3"},
                new string[] {"aaa", "qqq", "ccc"},
                new string[] {"qwer , 1234", @"aaa
 bbb", "qqq"}
            };

            var actual = target.Read(new StringReader(text)).ToArray();

            Assert.IsTrue(AreEqual(expected, actual));
        }
    }
}
